home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 8
/
Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso
/
Aminet
/
disk
/
cdrom
/
AmiCDROM_1_15.lha
/
AmiCDROM
/
src
/
checkcd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-03
|
12KB
|
486 lines
/* Checkcd.c:
*
* Performs consistency checks on a ISO 9660 CD.
*
* ----------------------------------------------------------------------
* This code is (C) Copyright 1994 by Frank Munkert.
* All rights reserved.
* This software may be freely distributed and redistributed for
* non-commercial purposes, provided this notice is included.
* ----------------------------------------------------------------------
* History:
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos/var.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include "cdrom.h"
#include "iso9660.h"
#include "rock.h"
#ifdef LATTICE
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
extern struct Library *SysBase, *DOSBase;
#endif
#define STD_BUFFERS 20
#define FILE_BUFFERS 2
CDROM *g_cd = NULL;
char g_the_device[80];
int g_the_unit;
t_ulong g_memory_type = MEMF_CHIP;
t_ulong g_check_sector;
char *g_check_name;
prim_vol_desc g_pvd;
int g_path_table_records = 0;
struct Library *UtilityBase;
#define TU(x,o) (t_ulong)(((unsigned char *)(x))[o])
#define GET721(x) (TU(x,0) + (TU(x,1) << 8))
#define GET722(x) (TU(x,1) + (TU(x,0) << 8))
#define GET731(x) (TU(x,0) + (TU(x,1) << 8) + (TU(x,2) << 16) + (TU(x,3) << 24))
#define GET732(x) (TU(x,3) + (TU(x,2) << 8) + (TU(x,1) << 16) + (TU(x,0) << 24))
/* Check consistency of a 7.2.3 field: */
void Check_723 (void *p_buf, int p_offset)
{
t_uchar *buf = (t_uchar *) (p_buf) + (p_offset - 1);
t_ulong l = buf[0] + (buf[1] << 8);
t_ulong m = buf[3] + (buf[2] << 8);
if (l != m) {
printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.2.3\n",
g_check_name, g_check_sector, p_offset);
}
}
/* Check consistency of a 7.3.3 field: */
void Check_733 (void *p_buf, int p_offset)
{
t_uchar *buf = (t_uchar *) p_buf + (p_offset - 1);
t_ulong l = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
t_ulong m = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
if (l != m) {
printf ("ERROR: %s, sector %lu, offset %d - not recorded according to 7.3.3\n",
g_check_name, g_check_sector, p_offset);
}
}
/* Check optional path tables: */
void Check_Optional_Path_Tables (void)
{
t_ulong loc1, loc2;
t_uchar *buf1;
t_uchar *buf2;
int i;
for (i=0; i<=1; i++) {
int remain = g_pvd.path_size_m;
if (i == 0)
loc1 = GET731((char*) &g_pvd.l_table),
loc2 = GET731((char *) &g_pvd.opt_l_table);
else
loc1 = g_pvd.m_table, loc2 = g_pvd.opt_m_table;
if (!loc2)
continue;
for (;;) {
if (!Read_Sector (g_cd, loc1)) {
printf ("ERROR: illegal sector %lu\n", loc1);
exit (1);
}
buf1 = g_cd->buffer;
if (!Read_Sector (g_cd, loc2)) {
printf ("ERROR: illegal sector %lu\n", loc2);
exit (1);
}
buf2 = g_cd->buffer;
if (memcmp (buf1, buf2, remain > 2048 ? 2048 : remain) != 0) {
printf ("ERROR: %c path table and optional %c path table differ"
" in sectors %lu and %lu\n",
i ? 'M' : 'L', i ? 'M' : 'L', loc1, loc2);
}
if (remain > 2048)
remain -= 2048;
else
break;
loc1++, loc2++;
}
}
}
/* Get the path table record in sector p_loc with offset *p_offset. */
void Get_Path_Table_Record (t_uchar *p_buf, t_ulong p_loc, t_ulong *p_offset)
{
t_ulong sector = p_loc + (*p_offset >> 11);
int len;
if (!Read_Sector (g_cd, sector)) {
printf ("ERROR: illegal sector %lu\n", sector);
exit (1);
}
len = g_cd->buffer[*p_offset & 2047] + 8;
if (len & 1)
len++;
if (len + (*p_offset & 2047) > 2048) {
int part1_len = 2048 - (*p_offset & 2047);
memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), part1_len);
if (!Read_Sector (g_cd, sector+1)) {
printf ("ERROR: illegal sector %lu\n", sector+1);
exit (1);
}
memcpy (p_buf + part1_len, g_cd->buffer, len - part1_len);
} else
memcpy (p_buf, g_cd->buffer + (*p_offset & 2047), len);
*p_offset += len;
}
/* Test whether the L and the M path tables contain the same information: */
void Compare_L_And_M_Path_Table (void)
{
t_ulong loc1 = GET731((char*) &g_pvd.l_table);
t_ulong loc2 = g_pvd.m_table;
t_ulong offset1 = 0;
t_ulong offset2 = 0;
static t_uchar buf1[256];
static t_uchar buf2[256];
while (offset1 < g_pvd.path_size_m) {
t_ulong tmp = offset1;
Get_Path_Table_Record (buf1, loc1, &offset1);
Get_Path_Table_Record (buf2, loc2, &offset2);
if (offset1 != offset2) {
printf ("ERROR: Length mismatch in L and M path table at offset %lu\n",
tmp);
return;
}
if (buf1[1] != buf2[1])
printf ("ERROR: Extended attribute record lengths differ in L and M"
" path table at offset %lu\n", offset1);
if (memcmp (buf1+8, buf2+8, buf1[0]) != 0)
printf ("ERROR: directory identifiers differ in L and M path table "
"at offset %lu\n", offset1);
if (GET731 (buf1+2) != GET732 (buf2+2))
printf ("ERROR: extent locations differ in L and M path table at"
" offset %lu\n", offset1);
if (GET721 (buf1+6) != GET722 (buf2+6))
printf ("ERROR: parent directory numbers differ in L and M path table at"
" offset %lu\n", offset1);
g_path_table_records++;
}
}
/* Check consistency of path table and directory records: */
void Compare_Path_Table_With_Directory_Records (void)
{
t_ulong loc = g_pvd.m_table;
t_ulong offset = 0;
static t_uchar buf[256];
int rec = 1;
VOLUME *vol;
CDROM_OBJ *obj;
CDROM_INFO info;
t_ulong pos;
t_bool warn_case = 0;
vol = Open_Volume (g_cd, 0);
if (!vol) {
printf ("ERROR: cannot open volume\n");
exit (10);
}
for (; offset < g_pvd.path_size_m; rec++) {
t_ulong tmp = offset;
if ((rec & 7) == 1) {
printf ("\r (%d of %d)",
rec, g_path_table_records);
fflush (stdout);
}
Get_Path_Table_Record (buf, loc, &offset);
/* skip root record: */
if (rec == 1)
continue;
pos = GET732 (buf+2);
obj = Iso_Create_Directory_Obj (vol, pos);
if (!obj || !CDROM_Info (obj, &info)) {
printf ("\nERROR: cannot get information for directory at location %lu\n"
"(Path table offset = %lu)\n", pos, tmp);
exit (10);
}
if (info.name_length != buf[0] ||
Strnicmp ((UBYTE*) info.name, (UBYTE*) buf+8, info.name_length) != 0) {
printf ("\nERROR: names in path table and directory record differ for "
"directory at location %lu\n", pos);
printf ("Name in path table = ");
fwrite (buf+8, 1, info.name_length, stdout);
printf ("\nName in directory record = ");
fwrite (info.name, 1, info.name_length, stdout);
putchar ('\n');
} else if (!warn_case && memcmp (info.name, buf+8, info.name_length) != 0) {
printf ("\nWARNING: Directory names in path table and directory records "
"differ in case.\n");
warn_case = 1;
}
Close_Object (obj);
}
printf ("\r%75s\r", "");
Close_Volume (vol);
}
/* Check optional path tables: */
void Check_Path_Tables (void)
{
Check_Optional_Path_Tables ();
Compare_L_And_M_Path_Table ();
}
/* Check primary volume descriptor: */
void Check_PVD (void)
{
int loc = 16;
int pvd_pos = 0;
prim_vol_desc *pvd;
do {
if (!Read_Sector (g_cd, loc)) {
printf ("ERROR: illegal sector %d\n", loc);
exit (1);
}
pvd = (prim_vol_desc *) g_cd->buffer;
if (memcmp (pvd->id, "CD001", 5) != 0) {
printf ("ERROR: missing standard identifier at sector %d\n", loc);
exit (10);
}
if (pvd->type > 4 && pvd->type < 255)
printf ("WARNING: unknown volume descriptor type at sector %d\n", loc);
if (pvd->version != 1)
printf ("WARNING: unknown volume descriptor version at sector %d\n", loc);
if (pvd->type == 1 && !pvd_pos)
pvd_pos = loc;
loc++;
} while (pvd->type != 255);
if (!Read_Sector (g_cd, pvd_pos)) {
printf ("ERROR: illegal sector %d\n", loc);
exit (1);
}
pvd = (prim_vol_desc *) g_cd->buffer;
g_check_name = "primary volume descriptor";
g_check_sector = pvd_pos;
Check_733 (pvd, 81);
Check_723 (pvd, 121);
Check_723 (pvd, 125);
Check_723 (pvd, 129);
Check_733 (pvd, 133);
memcpy (&g_pvd, pvd, sizeof (g_pvd));
}
void Check_Subdirectory (CDROM_OBJ *p_home, char *p_name)
{
CDROM_OBJ *obj;
CDROM_INFO info;
/* VOLUME *vol = p_home->volume; */
printf (" %s\r", p_name);
fflush (stdout);
if (obj = Open_Object (p_home, p_name)) {
unsigned long offset = 0;
while (Examine_Next (obj, &info, &offset)) {
directory_record *dir = info.suppl_info;
g_check_name = "directory record";
g_check_sector = offset;
Check_733 (dir, 3);
Check_733 (dir, 11);
Check_723 (dir, 29);
}
Close_Object (obj);
} else {
printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
return;
}
if (obj = Open_Object (p_home, p_name)) {
unsigned long offset = 0;
while (Examine_Next (obj, &info, &offset)) {
if (info.directory_f) {
char *name = malloc (strlen (p_name) + info.name_length + 2);
int len;
if (!name) {
fprintf (stderr, "out of memory\n");
exit (10);
}
if (Is_Top_Level_Object (obj))
name[0] = 0;
else
sprintf (name, "%s/", p_name);
len = strlen (name) + info.name_length;
memcpy (name + strlen (name), info.name, info.name_length);
name[len] = 0;
Check_Subdirectory (p_home, name);
free (name);
}
}
Close_Object (obj);
} else {
printf ("ERROR: Object '%s': iso_errno = %d\n", p_name, iso_errno);
}
printf (" %*s\r", strlen (p_name), "");
}
void Check_Directories (void)
{
VOLUME *vol;
CDROM_OBJ *home;
if (!(vol = Open_Volume (g_cd, 1))) {
printf ("ERROR: cannot open volume; iso_errno = %d\n", iso_errno);
exit (10);
}
if (!(home = Open_Top_Level_Directory (vol))) {
printf ("ERROR: cannot open top level directory; iso_errno = %d\n", iso_errno);
Close_Volume (vol);
exit (1);
}
Check_Subdirectory (home, ":");
Close_Object (home);
Close_Volume (vol);
}
void Cleanup (void)
{
if (g_cd)
Cleanup_CDROM (g_cd);
if (UtilityBase)
CloseLibrary (UtilityBase);
}
int Get_Device_And_Unit (void)
{
int len;
char buf[10];
len = GetVar ((UBYTE *) "CDROM_DEVICE", (UBYTE *) g_the_device,
sizeof (g_the_device), 0);
if (len < 0)
return 0;
if (len >= sizeof (g_the_device)) {
fprintf (stderr, "CDROM_DEVICE too long\n");
exit (1);
}
g_the_device[len] = 0;
len = GetVar ((UBYTE *) "CDROM_UNIT", (UBYTE *) buf,
sizeof (buf), 0);
if (len < 0)
return 0;
if (len >= sizeof (buf)) {
fprintf (stderr, "CDROM_UNIT too long\n");
exit (1);
}
buf[len] = 0;
g_the_unit = atoi (buf);
if (GetVar ((UBYTE *) "CDROM_FASTMEM", (UBYTE *) buf,
sizeof (buf), 0) > 0) {
fprintf (stderr, "using fastmem\n");
g_memory_type = MEMF_FAST;
}
return 1;
}
void main (int argc, char *argv[])
{
atexit (Cleanup);
if (!(UtilityBase = (struct Library *)
OpenLibrary ((UBYTE *) "utility.library", 37))) {
fprintf (stderr, "cannot open utility.library\n");
exit (1);
}
if (!Get_Device_And_Unit ()) {
fprintf (stderr,
"Please set the following environment variables:\n"
" CDROM_DEVICE name of SCSI device\n"
" CDROM_UNIT unit number of CDROM drive\n"
"e.g.\n"
" setenv CDROM_DEVICE scsi.device\n"
" setenv CDROM_UNIT 2\n"
"Set the variable CDROM_FASTMEM to any value if you\n"
"want to use fast memory for SCSI buffers (does not work\n"
"with all SCSI devices!)\n"
);
exit (1);
}
g_ignore_blocklength = TRUE;
g_cd = Open_CDROM (g_the_device, g_the_unit, 1, g_memory_type,
STD_BUFFERS, FILE_BUFFERS);
if (!g_cd) {
fprintf (stderr, "cannot open CDROM, error code = %d\n", g_cdrom_errno);
exit (1);
}
printf ("Checking primary volume descriptor...\n");
Check_PVD ();
printf ("Checking path tables...\n");
Check_Path_Tables ();
printf ("Comparing path table with directory records...\n");
Compare_Path_Table_With_Directory_Records ();
printf ("Checking directories...\n");
Check_Directories ();
printf ("All checks completed.\n");
exit (0);
}